#include "s3e.h"
#include <stdlib.h>

#define _SWAP(a,b) {int32 tmp = a; a = b; b = tmp;}

int32 PixelSize()
{
    int pxlType = s3eSurfaceGetInt(S3E_SURFACE_PIXEL_TYPE);
    
    switch(pxlType & S3E_SURFACE_PIXEL_SIZE_MASK) {
		case S3E_SURFACE_PIXEL_SIZE_8: return 1;
		case S3E_SURFACE_PIXEL_SIZE_16: return 2;
		case S3E_SURFACE_PIXEL_SIZE_24: return 3;
		case S3E_SURFACE_PIXEL_SIZE_32: return 4;
    }
    
    return 0;
}

// draw a line in uniform colour using Bressenham's algorithm
void DrawLineRGB(int32 x0, int32 y0, int32 x1, int32 y1, uint8 r, uint8 g, uint8 b )
{
    int32 pitch   = s3eSurfaceGetInt( S3E_SURFACE_PITCH );
    int pxlSize = PixelSize();
    uint32 col = s3eSurfaceConvertRGB(r,g,b);
    bool steep = false;

    if (abs(y1 - y0) > abs(x1 - x0)) {
        _SWAP(x0, y0)
        _SWAP(x1, y1)
        steep = true;
    }

    if (x0 > x1) {
        _SWAP(x0, x1)
        _SWAP(y0, y1)
    }

    int32 deltax = x1 - x0;
    int32 deltay = abs(y1 - y0);
    int32 error = deltax / 2;

    int32 _mx = steep ? pitch : pxlSize;
    int32 _my = steep ? pxlSize : pitch;
    int32 ystep = (y0 < y1) ? _my : -_my;
    uint8 *dest = ((uint8 *) s3eSurfacePtr()) + (x0 * _mx) + (y0 * _my);

    int32 x;
    switch (pxlSize)
    {
        case 1:
            for (x = x0; x <= x1; x++, dest += _mx) {
                *(uint8*)dest = (uint8)col;

                error -= deltay;

                if (error < 0) {
                    dest += ystep;
                    error += deltax;
                }
            }
            break;

        case 2:
            for (x = x0; x <= x1; x++, dest += _mx) {
                //don't make assumptions about alignment of dest
                *(uint8*)dest =     (uint8)col;
                *(uint8*)(dest+1) = (uint8)(col>>8);

                error -= deltay;

                if (error < 0) {
                    dest += ystep;
                    error += deltax;
                }
            }
            break;

        case 3:
            for (x = x0; x <= x1; x++, dest += _mx) {
                //don't make assumptions about alignment of dest
                *(uint8*)dest =     (uint8)col;
                *(uint8*)(dest+1) = (uint8)(col>>8);
                *(uint8*)(dest+2) = (uint8)(col>>16);

                error -= deltay;

                if (error < 0) {
                    dest += ystep;
                    error += deltax;
                }
            }
            break;

        case 4:
            for (x = x0; x <= x1; x++, dest += _mx) {
                //don't make assumptions about alignment of dest
                *(uint8*)dest =     (uint8)col;
                *(uint8*)(dest+1) = (uint8)(col>>8);
                *(uint8*)(dest+2) = (uint8)(col>>16);
                *(uint8*)(dest+3) = (uint8)(col>>24);

                error -= deltay;

                if (error < 0) {
                    dest += ystep;
                    error += deltax;
                }
            }
            break;

        default:
            break;
    }
}